/*
 * Copyright @ 2024 weili23
 * com.sky.service.impl 11:14
 * All right reserved.
 */

package com.sky.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.sky.constant.MessageConstant;
import com.sky.context.BaseContext;
import com.sky.dto.GoodsSalesDTO;
import com.sky.dto.OrdersSubmitDTO;
import com.sky.entity.AddressBook;
import com.sky.entity.OrderDetail;
import com.sky.entity.Orders;
import com.sky.entity.ShoppingCart;
import com.sky.exception.AddressBookBusinessException;
import com.sky.exception.ShoppingCartBusinessException;
import com.sky.mapper.AddressBookMapper;
import com.sky.mapper.OrderMapper;
import com.sky.service.OrderDetailService;
import com.sky.service.OrderService;
import com.sky.vo.OrderReportVO;
import com.sky.vo.OrderSubmitVO;
import com.sky.vo.SalesTop10ReportVO;
import com.sky.vo.TurnoverReportVO;
import com.sky.websocket.WebSocketServer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @desc:
 * @author: weili23
 * @createTime: 2024/11/11 11:14
 * @version: v1.0
 */
@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Orders> implements OrderService {

    @Resource
    private AddressBookMapper addressBookMapper;
    @Resource
    private OrderDetailService orderDetailService;
    @Resource
    private WebSocketServer webSocketServer;
    @Resource
    private OrderMapper orderMapper;
    @Override
    @Transactional
    public OrderSubmitVO orderSubmit(OrdersSubmitDTO ordersSubmitDTO) {
        Long userId = BaseContext.getCurrentId();

        //1.逻辑判断数据是否为空
        //判断用户的地址是否为空
        AddressBook addressBook = addressBookMapper.getById(ordersSubmitDTO.getAddressBookId());
        if(addressBook == null){
            throw new AddressBookBusinessException(MessageConstant.ADDRESS_BOOK_IS_NULL);
        }
        //判断用户购物车是否为空
        List<ShoppingCart> shoppingCarts = Db.lambdaQuery(ShoppingCart.class).eq(ShoppingCart::getUserId, userId).list();
        if(CollectionUtil.isEmpty(shoppingCarts)){
            throw new ShoppingCartBusinessException(MessageConstant.SHOPPING_CART_IS_NULL);
        }

        //2.插入订单数据
        Orders orders = new Orders();
        BeanUtil.copyProperties(ordersSubmitDTO,orders);
        orders.setAddress(addressBook.getDetail());
        orders.setOrderTime(LocalDateTime.now());
        orders.setConsignee(addressBook.getConsignee());
        orders.setUserId(userId);
        orders.setPhone(addressBook.getPhone());
        orders.setNumber(String.valueOf(System.currentTimeMillis()));
        orders.setStatus(Orders.PENDING_PAYMENT);
        this.save(orders);
        //3.插入订单详情数据 ，把购物车的数据插入订单详情表
        //组装订单详情list  批量插入
        List<OrderDetail> list = new ArrayList<>();
        for(ShoppingCart cards:shoppingCarts){
            OrderDetail orderDetail = new OrderDetail();
            BeanUtil.copyProperties(cards,orderDetail,"id");
            orderDetail.setOrderId(orders.getId());
            list.add(orderDetail);
        }
        orderDetailService.saveBatch(list);
        //组装返回vo
        OrderSubmitVO vo = OrderSubmitVO.builder()
                .id(orders.getId())
                .orderAmount(orders.getAmount())
                .orderTime(orders.getOrderTime())
                .orderNumber(orders.getNumber())
                .build();
        /*测试来单提醒 statr */
        Map<String,Object> map = new HashMap<>();
        //1来单提醒 2 催单
        map.put("type",1);
        map.put("orderId",vo.getId());
        map.put("content","订单号:"+vo.getOrderNumber());
        String s = JSONObject.toJSONString(map);
        webSocketServer.sendToAllClient(s);
        /* 测试来单提醒  end */
        return vo;
    }

    @Override
    public List<Orders> processOrderTimeOutTask(Integer state,LocalDateTime time) {
        //1.查询超时的订单
        List<Orders> list = this.lambdaQuery().eq(Orders::getStatus, state)
                .le(Orders::getOrderTime, time)
                .list();
       return list;
    }

    @Override
    public TurnoverReportVO getTurnOverStatistics(LocalDate begin, LocalDate end) {
        //时间拼接成list
        List<LocalDate> list = new ArrayList<>();
        list.add(begin);
        while(!begin.equals(end)){
            begin =begin.plusDays(1);
            list.add(begin);
        }
        //循环去查询每天的营业额
        List<Double> sumList = new ArrayList<>();
        for (LocalDate currentTime : list) {
            LocalDateTime startTime = currentTime.atStartOfDay();
            //LocalDateTime startTime1 = LocalDateTime.of(currentTime, LocalTime.MIN);
            LocalDateTime endTime = currentTime.atTime(LocalTime.MAX);
            //LocalDateTime endTime1 = LocalDateTime.of(currentTime, LocalTime.MAX);
            //log.info("startTime:{},startTime1:{},endTime:{},endTime1:{}",startTime,startTime1,endTime,endTime1);
            Double sum =orderMapper.getTurnOverStatistics(startTime,endTime,Orders.COMPLETED);
            sum = sum==null? 0.0:sum;
            sumList.add(sum);
        }
        return TurnoverReportVO
                .builder()
                .dateList(StringUtils.join(list,","))
                .turnoverList(StringUtils.join(sumList,","))
                .build();

    }

    @Override
    public OrderReportVO getOrdersStatistics(LocalDate begin, LocalDate end) {
        //时间拼接成list
        List<LocalDate> dateList = new ArrayList<>();
        dateList.add(begin);
        while(!begin.equals(end)){
            begin =begin.plusDays(1);
            dateList.add(begin);
        }
        List<Integer> orderCountList = new ArrayList<>();
        List<Integer> validOrderCountList = new ArrayList<>();
        //查询每天的订单统计
        for (LocalDate date : dateList) {
            LocalDateTime startTime = date.atStartOfDay();
            LocalDateTime endTime = date.atTime(LocalTime.MAX);
            Integer everydayOrderCount =  orderMapper.getOrdersStatistics(startTime,endTime,null);
            //有效订单是已完成订单 status=5
            Integer everydayValidOrderCount =  orderMapper.getOrdersStatistics(startTime,endTime,Orders.COMPLETED);
            orderCountList.add(everydayOrderCount);
            validOrderCountList.add(everydayValidOrderCount);
        }
        //计算时间区间内的订单总数 totalOrderCount
        Integer totalOrderCount = orderCountList.stream().reduce(Integer::sum).get();
        //计算时间区间内的有效订单总数 validOrderCount
        Integer validOrderCount = validOrderCountList.stream().reduce(Integer::sum).get();
        //计算完成率：Double orderCompletionRate;
        Double orderCompletionRate = 0.0;
        if(totalOrderCount != 0){
            orderCompletionRate = (double)(validOrderCount) / totalOrderCount;
        }
        return OrderReportVO.builder()
                .dateList(StringUtils.join(dateList,","))
                .validOrderCount(validOrderCount)
                .totalOrderCount(totalOrderCount)
                .validOrderCountList(StringUtils.join(validOrderCountList,","))
                .orderCountList(StringUtils.join(orderCountList,","))
                .orderCompletionRate(orderCompletionRate)
                .build();
    }

    @Override
    public SalesTop10ReportVO getTop10(LocalDate begin, LocalDate end) {
        List<GoodsSalesDTO> top10 = orderMapper.getTop10(begin.atStartOfDay(), end.atTime(LocalTime.MAX));
        /*//for循环处理
        List<String> name = new ArrayList<>();
        List<Integer> number = new ArrayList<>();
        for (GoodsSalesDTO salesDTO : top10) {
            name.add(salesDTO.getName());
            number.add(salesDTO.getNumber());
        }*/
        //用stream流实现
        List<String> name = top10.stream().map(GoodsSalesDTO::getName).collect(Collectors.toList());
        List<Integer> number = top10.stream().map(GoodsSalesDTO::getNumber).collect(Collectors.toList());

        return SalesTop10ReportVO.builder()
                .nameList(StringUtils.join(name,","))
                .numberList(StringUtils.join(number,","))
                .build();
    }
}
